/**
 * 
 */
package com.apinoo.users.dao;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.apinoo.basewebapp.spring.util.PaginationUtil;
import com.apinoo.users.domain.Group;
import com.apinoo.users.domain.User;
import com.apinoo.users.domain.UserGroup;
import com.apinoo.users.dto.UserDTO;
import com.apinoo.util.users.Constants;

/**
 * @author Alejandro Pino Oreamuno
 *
 */
@Repository
public class UserDAOImpl implements UserDAO {
	
	private Logger logger = Logger.getLogger(getClass());
	
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	@Override
	public User getUserById(long id) {
		User user = (User) this.sessionFactory.getCurrentSession()
				.get(User.class, id);
		
		return user;
	}

	/* (non-Javadoc)
	 * @see com.apinoo.users.dao.UsersDAO#getUserByUsername(java.lang.String)
	 */
	@Override
	public User getUserByUsername(String username) {
		User u = new User();
		Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(User.class);
		criteria.add(Restrictions.eq("username", username));

		u = (User) criteria.list().get(0);
		return u;
	}
	
	@Override
	public void addUser(UserDTO dto) {

		Session session = this.sessionFactory.getCurrentSession();
		List<UserGroup> listUserGroup = new ArrayList<UserGroup>();
		User newUser = new User();

		newUser = dto.getUser();
		newUser.setCreatedDate(new Timestamp(new Date().getTime()));
		// User-Group relationship
		listUserGroup = newUser.getListUserGroup();
		logger.info("listUserGroup size: "+ listUserGroup.size());
		for ( UserGroup ug : listUserGroup) {
			
			Group group = new Group();
			// Get group information
			group = (Group)session.get(Group.class, ug.getGroup().getIdGroup());
			logger.info("Group: "+ group.getIdGroup() + " : " + group.getName());
			ug.setUser(newUser);
			ug.setGroup(group);
			ug.setCreatedDate(new Timestamp(new Date().getTime()));
			ug.setCreatedBy(newUser.getCreatedBy());

		}	
		session.save(newUser);
	}

	@Override
	public void updateUser(UserDTO dto) {
		User userToUpdate = getUserById(dto.getUser().getIdUser());

		if ( !StringUtils.isBlank(dto.getUser().getUsername()))
			userToUpdate.setUsername(dto.getUser().getUsername());
		if ( !StringUtils.isBlank(dto.getUser().getEmail()))
			userToUpdate.setEmail(dto.getUser().getEmail());
		userToUpdate.setEnabled(dto.getUser().isEnabled());
		userToUpdate.setModifiedBy(dto.getUser().getModifiedBy());
		
		userToUpdate.setModifiedDate(new Timestamp(new Date().getTime()));
		
//		userToUpdate.setGroups(dto.getUser().getGroups());
		
		this.sessionFactory.getCurrentSession().update(userToUpdate);
	}

	@Override
	public void deleteUser(UserDTO dto) {
		
		User userToDelete = getUserById(dto.getUser().getIdUser());
		if ( dto != null) {
			this.sessionFactory.getCurrentSession().delete(userToDelete);
		}
	}

	@Override
	public List<UserDTO> getUsers(UserDTO dto) {
		Long idGroup = 0L;
		PaginationUtil pag = new PaginationUtil();

		Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(User.class);
		criteria.setFirstResult(pag.getFirstResult( dto.getStart() ));
		criteria.setMaxResults(10);
		
		if ( dto.getUser().getUsername() != null)
			if ( !dto.getUser().getUsername().equalsIgnoreCase(Constants.ALL))
				criteria.add(Restrictions.like(
						Constants.FIELD_USER_USERNAME, 
						dto.getUser().getUsername(), 
						MatchMode.ANYWHERE));
		
		if ( StringUtils.isNotBlank( dto.getUser().getEmail() ) )
			if ( !dto.getUser().getEmail().equalsIgnoreCase(Constants.ALL))
				criteria.add(Restrictions.like(
						Constants.FIELD_USER_EMAIL, 
						dto.getUser().getEmail(), 
						MatchMode.ANYWHERE));

		//FIXME
//		if ( dto.getUser().getGroups().size() > 0) {
//			for ( Group g : dto.getUser().getGroups())
//				idGroup = g.getIdGroup();
//
//			if ( idGroup > 0)
//				criteria.createAlias(Constants.TABLE_GROUPS, "grupos").add(Restrictions.eq(
//						"grupos.idGroup", 
//						idGroup));
//		}
		
		
		if ( dto.getOrderBy() == null ) criteria.addOrder(Order.asc(Constants.FIELD_USER_USERNAME));
		else if ( dto.getOrderBy().equals(Constants.ORDER_BY_USERNAME_DESC)) 
			criteria.addOrder(Order.desc(Constants.FIELD_USER_USERNAME));
		
		else if ( dto.getOrderBy().equals(Constants.ORDER_BY_GROUP_ASC)) {
			criteria.createAlias(Constants.TABLE_GROUPS, "grupos")
				.addOrder(Order.asc("grupos."+ Constants.FIELD_GROUP_NAME))
				.addOrder(Order.asc(Constants.FIELD_USER_USERNAME));
		}
			
			
		else if ( dto.getOrderBy().equals(Constants.ORDER_BY_GROUP_DESC)) {
			criteria.createAlias(Constants.TABLE_GROUPS, "grupos")
				.addOrder(Order.desc("grupos.name"))
				.addOrder(Order.asc("username"));
		}
		
		else if ( dto.getOrderBy().equals(Constants.ORDER_BY_EMAIL_ASC)) 
			criteria.addOrder(Order.asc(Constants.FIELD_USER_EMAIL));
		else if ( dto.getOrderBy().equals(Constants.ORDER_BY_EMAIL_DESC)) 
			criteria.addOrder(Order.desc(Constants.FIELD_USER_EMAIL));
		else if ( dto.getOrderBy().equals(Constants.ORDER_BY_CREATED_ASC)) 
			criteria.addOrder(Order.asc(Constants.FIELD_USER_CREATED));
		else if ( dto.getOrderBy().equals(Constants.ORDER_BY_CREATED_DESC)) 
			criteria.addOrder(Order.desc(Constants.FIELD_USER_CREATED));
		else criteria.addOrder(Order.asc(Constants.FIELD_USER_USERNAME));

		return criteria.list();
	}

	@Override
	public int countUsers(UserDTO dto) {
		Long idGroup = 0L;
		Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(User.class);
		
		if ( dto.getUser().getUsername() != null)
			if ( !dto.getUser().getUsername().equalsIgnoreCase("all"))
				criteria.add(Restrictions.like("username", dto.getUser().getUsername(), MatchMode.ANYWHERE));
		
		if ( StringUtils.isNotBlank( dto.getUser().getEmail() ) )
			if ( !dto.getUser().getEmail().equalsIgnoreCase("all"))
				criteria.add(Restrictions.like("email", dto.getUser().getEmail(), MatchMode.ANYWHERE));

		//FIXME
//		if ( dto.getUser().getGroups().size() > 0) {
//			for ( Group g : dto.getUser().getGroups())
//				idGroup = g.getIdGroup();
//
//			if ( idGroup > 0)
//				criteria.createAlias("groups", "grupos").add(Restrictions.eq("grupos.idGroup", idGroup));
//		}
		return criteria.list().size();
	}

	@Override
	public User getUserByEmail(String email) {
		Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(User.class);
		criteria.add(Restrictions.eq("email", email));
		
		if ( criteria.list().size() == 1)
			return (User) criteria.list().get(0);
		return null;
	}

	@Override
	public boolean validateUser(String username, String password) {
		String hql = "From User U WHERE U.username = :username AND U.password = :password";
		Query query = this.sessionFactory.getCurrentSession().createQuery(hql);
		query.setParameter("username", username);
		query.setParameter("password", password);
		
		if ( query.list().size() > 0)
			return true;
		
		return false;
	}

	@Override
	public boolean usernameExists(UserDTO dto) {
		Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(User.class);
		criteria.add(Restrictions.eq("username", dto.getUser().getUsername()));
		criteria.add(Restrictions.ne("idUser", dto.getUser().getIdUser()));
		
		if ( criteria.list().size() > 0) return true;
		
		return false;
	}

	@Override
	public boolean emailExists(UserDTO dto) {
		Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(User.class);
		criteria.add(Restrictions.eq("email", dto.getUser().getEmail()));
		criteria.add(Restrictions.ne("idUser", dto.getUser().getIdUser()));
		
		if ( criteria.list().size() > 0) return true;
		
		return false;
	}

}
